'use strict';

export function hexToRgb(hex) {
  const v = hex.startsWith('#') ? hex.slice(1) : hex;
  const r = parseInt(v.slice(0,2), 16);
  const g = parseInt(v.slice(2,4), 16);
  const b = parseInt(v.slice(4,6), 16);
  return { r, g, b };
}
function pivot(n){ n/=255; return (n<=0.04045)? n/12.92 : Math.pow((n+0.055)/1.055,2.4); }
function rgbToXyz({r,g,b}) {
  const R=pivot(r), G=pivot(g), B=pivot(b);
  return { X:(0.4124564*R+0.3575761*G+0.1804375*B)*100,
           Y:(0.2126729*R+0.7151522*G+0.072175*B)*100,
           Z:(0.0193339*R+0.119192*G+0.9503041*B)*100 };
}
function xyzToLab({X,Y,Z}) {
  const Xn=95.047, Yn=100, Zn=108.883;
  let x=X/Xn, y=Y/Yn, z=Z/Zn;
  const e=216/24389, k=24389/27;
  const fx=(x>e)? Math.cbrt(x) : (k*x+16)/116;
  const fy=(y>e)? Math.cbrt(y) : (k*y+16)/116;
  const fz=(z>e)? Math.cbrt(z) : (k*z+16)/116;
  return { L:116*fy-16, a:500*(fx-fy), b:200*(fy-fz) };
}
export function hexToLab(hex){ return xyzToLab(rgbToXyz(hexToRgb(hex))); }
export function deltaE2000(l1, l2) {
  const {L:L1,a:a1,b:b1}=l1, {L:L2,a:a2,b:b2}=l2;
  const avgL=(L1+L2)/2, C1=Math.hypot(a1,b1), C2=Math.hypot(a2,b2), avgC=(C1+C2)/2;
  const G=0.5*(1-Math.sqrt((avgC**7)/((avgC**7)+(25**7))));
  const a1p=(1+G)*a1, a2p=(1+G)*a2, C1p=Math.hypot(a1p,b1), C2p=Math.hypot(a2p,b2), avgCp=(C1p+C2p)/2;
  const h1p=(Math.atan2(b1,a1p)*180/Math.PI+360)%360, h2p=(Math.atan2(b2,a2p)*180/Math.PI+360)%360;
  const deltaLp=L2-L1, deltaCp=C2p-C1p;
  let deltahp;
  const dh=Math.abs(h2p-h1p);
  if (C1p*C2p==0) deltahp=0;
  else if (dh<=180) deltahp=h2p-h1p;
  else if (h2p<=h1p) deltahp=h2p-h1p+360;
  else deltahp=h2p-h1p-360;
  const deltaHp=2*Math.sqrt(C1p*C2p)*Math.sin((deltahp*Math.PI/180)/2);
  let Hpm;
  if (C1p*C2p==0) Hpm=h1p+h2p;
  else if (dh<=180) Hpm=(h1p+h2p)/2;
  else if ((h1p+h2p)<360) Hpm=(h1p+h2p+360)/2;
  else Hpm=(h1p+h2p-360)/2;
  const T=1-0.17*Math.cos((Hpm-30)*Math.PI/180)+0.24*Math.cos((2*Hpm)*Math.PI/180)
         +0.32*Math.cos((3*Hpm+6)*Math.PI/180)-0.20*Math.cos((4*Hpm-63)*Math.PI/180);
  const Sl=1+(0.015*((avgL-50)**2))/((20+(avgL-50)**2)**0.5);
  const Sc=1+0.045*avgCp;
  const Sh=1+0.015*avgCp*T;
  const dTheta=30*Math.exp(-(((Hpm-275)/25)**2));
  const Rc=2*Math.sqrt((avgCp**7)/((avgCp**7)+(25**7)));
  const Rt=-Rc*Math.sin(2*dTheta*Math.PI/180);
  const Kl=1, Kc=1, Kh=1;
  return ((deltaLp/(Kl*Sl))**2 + (deltaCp/(Kc*Sc))**2 + (deltaHp/(Kh*Sh))**2 + Rt*(deltaCp/(Kc*Sc))*(deltaHp/(Kh*Sh)))**0.5;
}
